/*
 * Copyright 2014 Geoff Capper.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.dlsc.gmapsfx.javascript.event;

import com.dlsc.gmapsfx.javascript.object.LatLong;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import netscape.javascript.JSObject;

/**
 * This object forms the bridge between Javascript events and the Java events.
 * <p>
 * An instance of this class is assigned to the document model so that
 * Javascript can access it to make callbacks when events occur.
 * <p>
 * An application calls on one of the two addXXEventHandler methods in the
 * {@link com.dlsc.gmapsfx.javascript.object.GoogleMap} class to register an
 * instance of the {@link GFXEventHandler} interface against a certain event
 * type in the Google Maps event model. See addUIEventHandler and
 * addStateEventHandler.
 * <p>
 * This class uses a key based on a UUID to map the Javascript event handlers
 * registered against the Google Maps model back to our Java event handlers
 * stored here. The addXXEventHandler methods in GoogleMap create functions that
 * call back into this class using the supplied key.
 * <p>
 * Currently an instance of this class is registered as:
 * <code>document.jsHandlers</code>
 * <p>
 * The event listeners are established using the following Javascript calls:
 * <p>
 * {@link com.dlsc.gmapsfx.javascript.object.GoogleMap#addUIEventHandler}
 * <p>
 * <blockquote><pre><code>
 * google.maps.event.addListener(map, 'event_type', function(event) {
 *      document.jsHandlers.handleUIEvent('key', event.latLng);
 * });
 * </code></pre></blockquote>
 * <p>
 * {@link com.dlsc.gmapsfx.javascript.object.GoogleMap#addStateEventHandler}
 * <p>
 * <blockquote><pre><code>
 *  google.maps.event.addListener(map, 'event_type', function() {
 *      document.jsHandlers.handleStateEvent('key');
 *  });
 * </code></pre></blockquote>
 *
 * @author Geoff Capper
 *
 */
public class EventHandlers {

    private final Map<String, GFXEventHandler> handlers = new HashMap<>();

    public EventHandlers() {
    }

    /**
     * Registers a handler and returns the callback key to be passed to
     * Javascript.
     *
     * @param handler Handler to be registered.
     * @return A String random UUID that can be used as the callback key.
     */
    public String registerHandler(GFXEventHandler handler) {
        String uuid = UUID.randomUUID().toString();
        handlers.put(uuid, handler);
        return uuid;
    }

    /**
     * This method is called from Javascript, passing in the previously created
     * callback key, and the event object. The current implementation is
     * receiving the LatLng object that the Javascript MouseEvent contains.
     * <p>
     * It may be more useful to return the MouseEvent and let clients go from
     * there, but there is only the stop() method on the MouseEvent?
     *
     * @param callbackKey Key generated by the call to registerHandler.
     * @param result Currently the event object from the Google Maps event.
     */
    public void handleUIEvent(String callbackKey, JSObject result) {
        if (handlers.containsKey(callbackKey) && handlers.get(callbackKey) instanceof UIEventHandler) {
            ((UIEventHandler) handlers.get(callbackKey)).handle(result);
        } else if (handlers.containsKey(callbackKey) && handlers.get(callbackKey) instanceof MouseEventHandler) {
            ((MouseEventHandler) handlers.get(callbackKey)).handle(buildMouseEvent(result));
        } else {
            System.err.println("Error in handle: " + callbackKey + " for result: " + result);
        }
    }

    /**
     * This method is called from Javascript, passing in the previously created
     * callback key. It uses that to find the correct handler and then passes on
     * the call. State events in the Google Maps API don't pass any parameters.
     *
     * @param callbackKey Key generated by the call to registerHandler.
     */
    public void handleStateEvent(String callbackKey) {
        if (handlers.containsKey(callbackKey) && handlers.get(callbackKey) instanceof StateEventHandler) {
            ((StateEventHandler) handlers.get(callbackKey)).handle();
        } else {
            System.err.println("Error in handle: " + callbackKey + " for state handler ");
        }
    }

    
    
    protected GMapMouseEvent buildMouseEvent(JSObject jsObject) {
        LatLong latLong = new LatLong((JSObject) jsObject.getMember("latLng"));
        return new GMapMouseEvent(latLong);
    }
}
